
#ifndef SX_BEZIER_CURVE_H
#define SX_BEZIER_CURVE_H

#include <sxPoint.h>

namespace Sx {
namespace Graphics {
namespace Objects {

/* 
 * Note about using the BezierCurve with a physical representation. The Bezier
 * curve defines the endpoints and control points of the curve. The physical
 * representation defines all of the discrete vertices that form the actual
 * curve.
 */
class BezierCurve : public GraphicsObject {
public:
	BezierCurve();
	BezierCurve(const Eigen::Vector3f& endPoint_0, const Eigen::Vector3f& endPoint_1);
	BezierCurve(const Eigen::Vector3f& endPoint_0, const Eigen::Vector3f& endPoint_1, const Eigen::Vector3f& controlPoint_0, const Eigen::Vector3f& controlPoint_1);
	virtual ~BezierCurve();

	/* Graphics Object Overrides */
	bool construct();
	void update(float dt);

	/* This function constructs a Bezier curve that is a straight line. */
	void setLine(const Eigen::Vector3f& endPoint_0, const Eigen::Vector3f& endPoint_1);

	/* Defines the curve based on the two end points and two control points. */
	void setCurve(const Eigen::Vector3f& endPoint_0, const Eigen::Vector3f& endPoint_1, const Eigen::Vector3f& controlPoint_0, const Eigen::Vector3f& controlPoint_1);

	/* Set the end points of the curve. */
	void setEndPoint(bool index, const Eigen::Vector3f& point);
	void setEndPointPrimary(const Eigen::Vector3f& point);
	void setEndPointSecondary(const Eigen::Vector3f& point);
	void setEndPoints(const Eigen::Vector3f& endPoint_0, const Eigen::Vector3f& endPoint_1);
	
	/* Set the control points of the curve. */
	void setControlPoint(bool index, const Eigen::Vector3f& controlPoint);
	void setControlPointPrimary(const Eigen::Vector3f& controlPoint);
	void setControlPointSecondary(const Eigen::Vector3f& controlPoint);
	void setControlPoints(const Eigen::Vector3f& controlPoint_0, const Eigen::Vector3f& controlPoint_1);

	void setSelected(bool ep0, bool ep1, bool cp0, bool cp1);
	void setEndPointSelected(bool index, bool selected);
	void setControlPointSelected(bool index, bool selected);
	bool isEndPointSelected(bool index) const;
	bool isControlPointSelected(bool index) const;

	void select();
	void deselect();

	void setOneToOneFunction(bool b);
	void setHasLoop(bool b);
	bool isOneToOneFunction() const;
	bool hasLoop() const;

	/* Get end point information. */
	Point& endPoint(bool index);
	Point& endPointPrimary();
	Point& endPointSecondary();
	const Point& getEndPoint(bool index) const;
	const Point& getEndPointPrimary() const;
	const Point& getEndPointSecondary() const;

	/* Get control point information. */
	Point& controlPoint(bool index);
	Point& controlPointPrimary();
	Point& controlPointSecondary();
	const Point& getControlPoint(bool index) const;
	const Point& getControlPointPrimary() const;
	const Point& getControlPointSecondary() const;

protected:
	void initialize();

	/* 
	 * The mathematical transformations of these points should be left as the
	 * identity.
	 */
	Point endPoint_0, endPoint_1;
	Point controlPoint_0, controlPoint_1;

	/*
	 * True if this curve can be used as a 1-to-1 function; false otherwise.
	 * This is set as a bool flag because it depends on the approximate
	 * representation of the curve. This class only defines the abstract
	 * characteristics of a single Bezier curve.
	 */
	bool oneToOneFunction;

	/* 
	 * True if this curve contains a loop based on the position of the two
	 * control points; otherwise false. This is set as a bool flag because
	 * it depends on the approximate representation of the curve provided
	 * by a graphics implementation. It can be calculated, however it will
	 * incur the penalty of computing the interpolation.
	 */
	bool looped;
};

}

}

}

#endif
